#ifndef RACE_H
#define RACE_H 1

#include "ADDObjetBase.h"

#include <iostream>
#include <vector>
#include <map>

//#include "lib.h"
#include "Prerequis.h"
/* #include "ListCapa.h" */
/* #include "ListEnsCapa.h" */
#include "CapaciteRaciale.h"
#include "EnsembleCapacitesRaciales.h"
#include "StatusCode.h"

//#include "debugstreams.h"

//#include <boost/assign/list_of.hpp>

using namespace std;

/**
 * La classe Race représente une race au sens AD&D. C'est une classe
 * abstraite, qui sert au polymorphisme.
 *
 * La classe permet de gérer les diverses capacités raciales et
 * éventuels ensembles raciaux, qui sont lus depuis les types de
 * races. L'accès à une race donnée est géré par des prérequis (bornes
 * inférieures et supérieures à la valeur de certains traits), aussi
 * lus depuis les classes dérivées. Le choix d'une race particulière
 * peut modifier les traits, ces ajustements sont appliqués
 * automatiquement lors de la construction, les valeurs sont une fois
 * encore lues depuis la classe dérivée. Finalement certaines races
 * peuvent avoir un bonus exceptionel sur un trait, moyennant la
 * pocession d'une compétence donnée (généralement très chère), les
 * paramètres régissant ce bonue exceptionnel sont également déterminé
 * par la classe dérivée.
 *
 * L'objet Race possède les méthodes et attributs communs à toutes les
 * races.
 *
 * @author Johan "Solo" Luisier
 */
class Race : public ADDObjetBase
{
 protected:
  /**
   * Permet de déterminer si les niveaux de sorties ont bien été
   * initialisés.
   */
  static bool NiveauxLus;
  /**
   * Liste des noms des niveaux de sorties paramétrables.
   */
  static const vector< string > NomsNiveaux;
  /**
   * Valeur retournée lorsque l'on demande le numéro d'une capacité
   * inexistante. La valeur est 0xFFFF, car avant on encodait les
   * capacités sur des unsigned short.
   */
  static const unsigned PasTrouve;
  /**
   * Structure qui permet de gérer les éventuel bonus pour un trait,
   * qui serait dû à une compétence spécifique. Par exemple un Elfe
   * qui prend la capacité raciale "Dextérité renforcée" (pour 20 pp)
   * a \f$ + 1 \f$ en dextérité. On doit donc stocker dans cette
   * structure le trait potentiellement augmenté, l'éventuel bonus et
   * le numéro de la capacité de laquelle découle le bonus.
   */
  struct BonusConditionnel
  {
    unsigned TraitNumero; /**< Numéro du trait à modifier */
    unsigned CapaNumero;  /**< Numéro de la capacité raciale
			     déclenchante. */
    int Ajustement;       /**< Ajustement au trait (\f$ +1 \f$
			     généralement). */
  };
  /**
   * Capacités raciales. On stocke uniquement le numéro de la capacité
   * dans ce conteneur.
   */
  vector<unsigned> Capacites;
  /**
   * Niveau de sortie des méthodes de base, c'est à dire très
   * simple. On peut changer la valeur de cette constante en modifiant
   * la ligne Race::élémentaire du fichier CONFIG.
   */
  static DebugLevelType elementaire;
  /**
   * Niveau de sortie des fonctions plus élaborées. La valeur de cette
   * constante est définie par la ligne Race::fonction du fichier
   * CONFIG.
   */
  static DebugLevelType fonction;
  /**
   * Nom de la Race (Elfe, Gnome, Humain, ...)
   */
  string Type;
  /**
   * Nombre de points de personnages (PP) disponible pour la création
   * de la Race.
   */
  unsigned NombrePPsAlloues;
  /**
   * Contient le nombre de capacités raciales disponibles lors de la
   * création.
   */
  unsigned NombreTotalCapacites;
  /**
   * Nombre d'ensembles raciaux, est égal au nombre de lignes de la
   * matrice EnsemblesRaciaux.
   */
  unsigned NombreTotalEnsembles;
  /**
   * Nombre maximal de capacités raciales dans un ensemble racial.
   */
  unsigned NombreMaxCapacites;
  /**
   * Contient les capacités raciales, permet d'avoir accès aux
   * capacités (noms, cout en pp) de la race considérée.
   */
  vector< CapaciteRaciale > CapacitesRaciales;
  /**
   * Contient les ensembles raciaux, permet d'avoir accès aux noms et
   * coûts des ensembles, ainsi qu'aux capacités incluses.
   */
  vector< EnsembleCapacitesRaciales > EnsemblesRaciaux;
  /**
   * Contient la liste des prérequis raciaux. Cela permet d'éviter de
   * créer un Demi-Ogre avec 20 de Charisme par exemple.
   */
  vector< Prerequis > PrerequisRaciaux;
  /**
   * Contient les ajustements raciaux sur les traits.
   */
  map< unsigned, int > AjustementsRaciaux;
  /**
   * Pointeur sur l'éventuel bonus sur un trait. L'existence de ce
   * bonus dépend de la race et de la présence d'une capacité raciale
   * spécifique.
   */
  BonusConditionnel* BonusAuTrait;
 public:
  /*
   * Construction / destruction de l'objet
   */
  Race( const string& type );
  Race( const Race& race );
  virtual ~Race();
  void construitRace( unsigned& pps );

  /*
   * Accesseurs
   */
  unsigned tailleCapacites() const;
  const unsigned& numCapacite( const unsigned& i ) const;
  const unsigned& pp() const;
  const string& type() const;
  const string& nomCapacite( const unsigned& i ) const;
  const CapaciteRaciale& capaciteNumero( const unsigned& i ) const;

  const unsigned& nombrePPsAlloues() const;

  const vector< unsigned >* adresseCapacites() const;
  const vector< unsigned >* capacites( unsigned& nbr ) const;

  void copieCapacitesRaciales( unsigned& nbr, vector< CapaciteRaciale >& capa ) const;
  const vector< CapaciteRaciale >* capacitesRaciales() const;

  void donneesEnsRaciaux( unsigned& nbr, unsigned& max ) const;
  const vector< EnsembleCapacitesRaciales >* ensemblesRaciaux() const;

  void copiePrerequisRaciaux( vector< Prerequis >& prerequis ) const;
  void copieAjustementsRaciaux( map< unsigned, int >& ajustements ) const;

  /*
   * Affichage
   */
  void afficheInfo( ostream& os ) const;
  void afficheInfo( FlotMessage& flot ) const;

  /*
   * Modificateurs
   */
  void setCapacites( const vector<unsigned>& capa );
  static void setLevel( const unsigned& level, const unsigned& n );

  StatusCode rempliPrerequis( vector< unsigned >& tab );
  void appliquerAjustements( vector< unsigned >& tab );
};


#endif // RACE_H
